package org.example.core;

import java.util.Arrays;

/**
 * FAT表管理类 - 管理文件分配表
 * 简单来说，这个FAT表管理类负责管理文件分配表，包括加载、保存、初始化FAT表，以及查询和修改FAT表中的块状态。
 */
public class FATManager {
    private byte[] fatTable; // FAT表数据
    private DiskEmulator disk; // 磁盘模拟器

    // FAT表常量
    // 实验文档提到：
    // 空闲块：值为0
    // 文件结束块：值为0xFF，即数字255，用于标记文件的结束
    // 坏块：值为0xFE，即数字254，用于标记损坏的块
    public static final byte FREE_BLOCK = 0; // 空闲块
    public static final byte END_OF_FILE = (byte) 0xFF; // 文件结束块
    public static final byte BAD_BLOCK = (byte) 0xFE; // 坏块

    public FATManager(DiskEmulator disk) {
        this.disk = disk;
        this.fatTable = new byte[128]; // 128个块
        loadFAT(); // 加载FAT表
    }

    /**
     * 从磁盘加载FAT表
     */
    private void loadFAT() {
        try {
            // FAT表占用块0和块1
            byte[] block0 = disk.readBlock(0);
            byte[] block1 = disk.readBlock(1);

            // 将两个块的数据合并到fatTable
            System.arraycopy(block0, 0, fatTable, 0, 64);
            System.arraycopy(block1, 0, fatTable, 64, 64);

            System.out.println("FAT表加载成功");
        } catch (Exception e) {
            System.err.println("加载FAT表失败: " + e.getMessage());
            // 初始化一个空的FAT表
            initializeFAT();
        }
    }

    /**
     * 初始化FAT表
     */
    private void initializeFAT() {
        Arrays.fill(fatTable, FREE_BLOCK); // 初始化所有块为空闲块

        // 标记系统块(0和1)为已使用，原因：系统块0和1用于存储FAT表，不能被普通文件使用
        fatTable[0] = END_OF_FILE; // 系统块0标记为文件结束
        fatTable[1] = END_OF_FILE; // 系统块1标记为文件结束

        // 标记坏块(23和49)，原因：实验文档提到23和49是坏块
        fatTable[23] = BAD_BLOCK; // 坏块23
        fatTable[49] = BAD_BLOCK; // 坏块49

        System.out.println("FAT表初始化完成");
    }

    /**
     * 保存FAT表到磁盘
     */
    public void saveFAT() {
        try {
            byte[] block0 = new byte[64]; // 系统块0，用于存储FAT表
            byte[] block1 = new byte[64]; // 系统块1，用于存储FAT表

            System.arraycopy(fatTable, 0, block0, 0, 64);
            System.arraycopy(fatTable, 64, block1, 0, 64);

            disk.writeBlock(0, block0);
            disk.writeBlock(1, block1);

            System.out.println("FAT表保存成功");
        } catch (Exception e) {
            System.err.println("保存FAT表失败: " + e.getMessage());
        }
    }

    /**
     * 分配一个空闲块
     */
    public int allocateBlock() {
        for (int i = 2; i < fatTable.length; i++) {
            if (fatTable[i] == FREE_BLOCK) {
                fatTable[i] = END_OF_FILE;
                return i;
            }
        }
        return -1; // 没有空闲块
    }

    /**
     * 释放一个块
     */
    public void freeBlock(int blockNumber) {
        if (blockNumber >= 2 && blockNumber < fatTable.length) {
            fatTable[blockNumber] = FREE_BLOCK;
        }
    }

    /**
     * 获取下一个块号
     */
    public int getNextBlock(int currentBlock) {
        if (currentBlock < 0 || currentBlock >= fatTable.length) {
            return -1;
        }
        return fatTable[currentBlock] & 0xFF; // 转换为无符号整数
    }

    /**
     * 设置下一个块号
     */
    public void setNextBlock(int currentBlock, int nextBlock) {
        if (currentBlock >= 0 && currentBlock < fatTable.length) {
            fatTable[currentBlock] = (byte) nextBlock;
        }
    }

    /**
     * 获取空闲块数量
     */
    public int getFreeBlockCount() {
        int count = 0;
        for (int i = 2; i < fatTable.length; i++) {
            if (fatTable[i] == FREE_BLOCK) {
                count++;
            }
        }
        return count;
    }

    /**
     * 获取FAT表状态（用于显示）
     */
    public String getFATStatus() {
        StringBuilder status = new StringBuilder();
        status.append("FAT表状态:\n");

        for (int i = 0; i < fatTable.length; i++) {
            if (i % 16 == 0) {
                status.append("\n");
            }

            String value;
            switch (fatTable[i] & 0xFF) {
                case FREE_BLOCK: value = "FREE"; break;
                case END_OF_FILE: value = "EOF"; break;
                case BAD_BLOCK: value = "BAD"; break;
                default: value = String.format("%3d", fatTable[i] & 0xFF);
            }

            status.append(String.format("[%3d:%4s] ", i, value));
        }

        return status.toString();
    }

    /**
     * 获取FAT表数据的副本
     */
    public byte[] getFATTable() {
        return Arrays.copyOf(fatTable, fatTable.length);
    }
}
